home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / lists / mint / l_0799 / 574 < prev    next >
Encoding:
Internet Message Format  |  1994-08-27  |  7.3 KB

  1. Subject: Re: i/o speed (was: pipes & ptys)
  2. Date: Fri, 22 Oct 93 23:07:36 CET
  3. From: Juergen Lock <nox@jelal.north.de>
  4. In-Reply-To: <9310221236.AA17935@dohle.techfak.uni-bielefeld.de>; from "itschere@TechFak.Uni-Bielefeld.DE" at Oct 22, 93 1:36 pm
  5. Message-Id: <9310222207.AA00138@jelal.north.de>
  6.  
  7. itschere@TechFak.Uni-Bielefeld.DE writes:
  8. > Juergen Lock
  9. > > > Ok, got this, but: (see my other mail) it will return as soon as ther is
  10. > > > some data, say, when it get's its next time slice, which is 16ms long on
  11. > > > my 60Hz TT-VBL, right? Now I estimate that the writer (if really using 1
  12. > > > bytes I/O), doesn't manage to output more than something like 30 chars per
  13. > > > timeslice, so 60 slices a 30 bytes (always completely ignoring the time
  14. > > > I need to read the data),~
  15. > >
  16. > >  this is the time we're trying to improve...
  17. > feel free to do so... :-)
  18. > > > makes 1800 CPS, and that looks like the number I've measured.
  19. > >
  20. > >  how much cps does the writer get when you send it to /dev/null
  21. > > instead?  the difference between that and your 1800 is the only thing
  22. > > we can improve here of course... for more the writing program has to
  23. > > use longer writes.
  24. > naturally more, don't know exactly, but sure not 10 times as much... :-(
  25. > to summarize it:
  26. > if a program chooses to output one char, say, through a piped pseudo
  27. > terminal, it looks more or less like this:
  28. > Cconout('!') ->
  29. > Fwrite(?, 1, "!") ->
  30. > tty_write(...) ->
  31. > tty_putchar() ->
  32. > pipe_write().
  33.  
  34.  (actually Cconout doesn't go thru Fwrite but its still slow.)
  35. > and the reader get's:
  36. > Fread() ->
  37. > tty_read() ->
  38. > tty_getchar() ->
  39. > pipe_read().
  40.  
  41.  ...only the reader can be improved.
  42.  
  43.  Fread() ->
  44.  tty_read() ->
  45.  one pty_bread().
  46. > and in the meantime, half an hour is gone... ;-(
  47. > > > If a) you really use big chunks and b) modems are operated by interrupt...
  48. > > 
  49. > >  yup!  actually modems are operated by interrupts already, only
  50. > > the buffer status is still polled and data is read/written
  51. > > one-byte-at-a-time...
  52. > to be more accurate, only incoming bytes raise an interrupt, but for outgoing
  53. > the i/o chip is polled to see if it's ready. perhaps not immediately after the
  54. > byte was send away, but before a char is to be send.
  55.  
  56.  thats true for the midi port and keyboard controller but...
  57.  
  58. >  at least the MFP does also
  59. > support an interrupt for "output-buffer-empty", the newer chips also, I think.
  60.  
  61.  (any serial port chip has that :)
  62.  
  63. > but as far as I know, these are not used so far.
  64.  
  65.  ...but the modem port(s) do use send buffers.  not that ataris BIOS
  66. modem drivers are known to be fast and bug-free but they do use the rx
  67. and tx interrupts...
  68. > by using these and a new buffer managing, completely obsoleting the bios,
  69. > you'll gain lots of speed, I presume... :-)
  70.  
  71.  yup.  and if the device can get around all the char <-> long `conversions'
  72. etc so that a Fwrite can end up as just a few movem.l (bcopy...) you get
  73. even more speed.  this is the write() replacement i have in uucp:
  74.  
  75. #if MINT_FASTWRITE
  76. /* here is fastwrite()...  comments like on fastread() apply. */
  77. int fastwrite (fd, buf, cwrite, qs)
  78. int fd;
  79. char *buf;
  80. unsigned cwrite;
  81. struct ssysdep_serial_port *qs;
  82. {
  83.   char *p = buf;
  84.   int slept = 0;
  85.  
  86.   /* /dev/midi doesn't have a write buffer :-( */
  87.   if (!S_iorec || S_biosdev == 3)
  88.     return write (fd, buf, cwrite);
  89.  
  90.   /* if we should watch CD and its not there flush buffers and return 0. */
  91.   if (buf && S_fwatchcd && !pollcd (S_biosdev)) {
  92. #if MINT_FASTREAD
  93.     (void) fastread (fd, (char *) NULL, 0, qs);
  94. #endif
  95.     buf = (char *) NULL;
  96.   }
  97.  
  98.   if (!buf) {
  99.     long stack = Super (0L);
  100.  
  101.     /* flush send buffer...  should be safe to just set the tail pointer. */
  102.     S_iorec[1].ibuftl = S_iorec[1].ibufhd;
  103.     (void) Super (stack);
  104.     return 0;
  105.   }
  106.  
  107.   if (!cwrite)
  108.     /* nothing to do... */
  109.     return 0;
  110.  
  111.   do {
  112.     char ch;
  113.     unsigned short tail, bsize, wrap, newtail;
  114.     long free, stack;
  115.  
  116.     /* enter supervisor mode... */
  117.     stack = Super (0L);
  118.  
  119.     tail = S_iorec[1].ibuftl;
  120.     bsize = S_iorec[1].ibufsiz;
  121.     if ((free = S_iorec[1].ibufhd - tail - 1) < 0)
  122.       free += bsize;
  123.  
  124.     /* if buffer is full or we're blocking and can't write enuf */
  125.     if (!free || (qs->fread_blocking && free < cwrite && free < bsize/2)) {
  126.       long sleepchars;
  127.       unsigned isleep;
  128.  
  129.       /* leave super mode. */
  130.       (void) Super (stack);
  131.  
  132.       /* if the write should not block thats it. */
  133.       if (!qs->fread_blocking)
  134.     return p - buf;
  135.  
  136.       /* else sleep the (minimum) time it takes until the buffer is
  137.      either half-empty or has space enough for the write, wichever
  138.      is smaller. */
  139.       if ((sleepchars = bsize/2) > cwrite)
  140.     sleepchars = cwrite;
  141.       sleepchars -= free;
  142.  
  143.       isleep = (unsigned) ((sleepchars * 10000L) / qs->ibaud);
  144.  
  145.       /* except that if we already slept and the buffer still was full we
  146.      sleep for at least 20 milliseconds. (driver must be waiting for
  147.      some handshake signal and we don't want to hog the processor.) */
  148.       if (slept && isleep < 20)
  149.     isleep = 20;
  150.  
  151.       if (isleep < 5)
  152.     /* if it still would be less than 5 milliseconds then just
  153.        give up this timeslice */
  154.     (void) Syield();
  155.       else
  156.     usleep ((unsigned long) isleep * 1000);
  157.  
  158.       /* loop and try again. */
  159.       slept = !free;
  160.       continue;
  161.     }
  162.     slept = 0;
  163.  
  164.     /* save the 1st char, we could need it later. */
  165.     ch = *p;
  166.     wrap = bsize - tail;
  167.     if (free > cwrite)
  168.       free = cwrite;
  169.     cwrite -= free;
  170.  
  171.     /* now copy to buffer.  if its just a few then do it here... */
  172.     if (free < 5) {
  173.       char *q = S_iorec[1].ibuf + tail;
  174.  
  175.       while (free--) {
  176.     if (!--wrap)
  177.       q -= bsize;
  178.     *++q = *p++;
  179.       }
  180.       newtail = q - S_iorec[1].ibuf;
  181.  
  182.     /* ...else use bcopy. */
  183.     } else {
  184.       /* --wrap and tail+1 because tail is `inc before access' */
  185.       if (--wrap < free) {
  186.     bcopy (p, S_iorec[1].ibuf + tail + 1, wrap);
  187.     bcopy (p + wrap, S_iorec[1].ibuf, free - wrap);
  188.     newtail = free - wrap - 1;
  189.       } else {
  190.     bcopy (p, S_iorec[1].ibuf + tail + 1, free);
  191.     newtail = tail + free;
  192.       }
  193.       p += free;
  194.     }
  195.  
  196.     /* the following has to be done with interrupts off to avoid
  197.        race conditions. */
  198.     {
  199.       short sr = intsoff ();
  200.  
  201.       /* if the buffer is empty there might be no interrupt that sends
  202.      the next char, so we send it thru the xcon* vector. */
  203.       if (S_iorec[1].ibufhd == S_iorec[1].ibuftl) {
  204.     (void) xcon_exec (S_bioswrite, (unsigned char) ch);
  205.  
  206.     /* if the buffer now is still empty we must set the head pointer
  207.        to skip the 1st char (that we just sent). */
  208.     if (S_iorec[1].ibufhd == S_iorec[1].ibuftl) {
  209.       if (++tail >= bsize)
  210.         tail = 0;
  211.       S_iorec[1].ibufhd = tail;
  212.     }
  213.       }
  214.       S_iorec[1].ibuftl = newtail;
  215.  
  216.       intson (sr);
  217.     }
  218.     (void) Super (stack);
  219.  
  220.   /* if we may block loop until everything is written */
  221.   } while (cwrite && qs->fread_blocking);
  222.  
  223.   return p - buf;
  224. }
  225. #endif /* MINT_FASTWRITE */
  226. #endif /* __MINT__ */
  227.  
  228.  when this is constantly sending ~2000 cps on modem2 the process
  229. (uucico) takes 4 or 5 % CPU according to `top'.  (megaSTe, uucp-g with
  230. 1K packets and window 7.  receiving takes more.)
  231.  
  232.  maybe people understand better now why i call unnecessary char <-> long
  233. shuffling overhead... :-)
  234.  
  235.  cheers
  236.     Juergen
  237. -- 
  238. J"urgen Lock / nox@jelal.north.de / UUCP: ..!uunet!unido!uniol!jelal!nox
  239.                                 ...ohne Gewehr
  240. PGP public key fingerprint =  8A 18 58 54 03 7B FC 12  1F 8B 63 C7 19 27 CF DA 
  241.